#include <opencv2/opencv.hpp>
#include "cpp_plugin_interface.hpp"
#include <string>
#include <iostream>
#include <memory>
#include <Windows.h>
#include <filesystem>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
using namespace std;
using namespace cv;
namespace fs = std::filesystem;

vector<string> dll_files;
std::vector<HINSTANCE> plugin_dll_handles;//析构时记得用FreeLibrary释放
std::vector<std::shared_ptr<std::vector<cpp_plugin::interface_t *> > > plugin_instance_list;

int main(int argn, const char **argv) {
    system("chcp 65001");// 将控制台修改为utf8编码
    try {
        cout << "加载DLL中..." << endl;
        //查找DLL
        for (auto i: {"./", "./../plugin", "./plugin"}) {
            if (fs::exists(i))
                for (auto const &dir_entry: fs::directory_iterator{i}) {
                    if ((!dir_entry.is_directory()) &&
                        (dir_entry.path().string().find(".dll") != string::npos)) {
                        dll_files.push_back(dir_entry.path().string());
                        cout << dir_entry.path().string() << endl;
                    }
                }
        }

        for (auto &i: dll_files) {
            HINSTANCE hDll = LoadLibrary(i.c_str());// 加载DLL库文件
            if (hDll == nullptr)
                continue;
            using get_instance_t = decltype(get_cpp_plugin_instance_lists);
            using instance_deletor_t = decltype(get_cpp_plugin_instance_deletor);
            auto *get_instance = (get_instance_t *) GetProcAddress(
                    hDll, "get_cpp_plugin_instance_lists");// 将指针指向函数首地址
            auto *instance_deletor = (instance_deletor_t *) GetProcAddress(
                    hDll, "get_cpp_plugin_instance_deletor");// 将指针指向函数首地址
            if (get_instance == nullptr || instance_deletor == nullptr) {
                FreeLibrary(hDll);
                continue;
            }
            cout << "发现插件dll:" << i << endl;
            plugin_dll_handles.push_back(hDll);
            plugin_instance_list.push_back(std::shared_ptr<std::vector<cpp_plugin::interface_t *> >(
                    get_instance(), instance_deletor
            ));
        }

        cout << "以下为扫描到的图像算子" << endl;
        for (auto &i: plugin_instance_list) {
            for (auto instance: *i) {
                cout << instance->get_name() << "\t:" << instance->get_help_info() << endl;
            }
        }
        string file;
        Mat mat;
        if (argn == 2) {
            mat = imread(argv[1], cv::IMREAD_COLOR);
        }
        while (mat.empty()) {
            cout << endl << "测试开始,请输入测试图片(无中文路径)" << endl;
            getline(cin, file);
            mat = imread(file, cv::IMREAD_COLOR);
            if (mat.empty())
                cout << "图片无效" << endl;
        };

        imshow("原图", mat);
        Mat result;
        for (auto &i: plugin_instance_list) {
            for (auto instance: *i) {
                auto j = json::parse(instance->get_description_json());
                cout << "执行:" << instance->get_name() << "  " << j.at("arg_default") << endl;
                result = instance->process(mat, j.at("arg_default"));
                imshow(instance->get_name(), result);
            }
        }
        waitKey();
        //先释放插件实例
        for (auto &i: plugin_instance_list) {
            i.reset();
        }
        //后释放dll
        for (auto i: plugin_dll_handles) {
            FreeLibrary(i);
        }
    }
    catch (const std::exception &e) {
        std::cerr << e.what() << std::endl;
        system("pause");
    }
    return 0;
}